import WebMercatorProjection from '../lib/cesium/Core/WebMercatorProjection.js';
import { convertLngLatToNswe } from '../lib/util/ToolMethods.js';
import { UnitsUtils } from '../../../modules/geo-three/geo-three.module.js';
import proj4 from '../../../modules/proj4/proj4-module.js';
import * as THREE from "../../../modules/three/three.module.js";
import { WorldConfig, epsg_4544, r2d } from '../lib/CommonConsts.js';
import Cartesian3 from '../lib/cesium/Core/Cartesian3.js';
import Cartographic from '../lib/cesium/Core/Cartographic.js';
import SimpleMarkEntity from '../lib/gadget/SimpleMarkEntity.js';
import {
  createContourLineSegments, createLocationSprite,
  createTextSprite,
  getPositionMarker, getYAngleDeg,
} from '../lib/util/StaticMethods.js';
import PlaneRefMesh from "../lib/gadget/PlaneRefMesh.js";
import WorkAreaMesh from "../lib/gadget/WorkAreaMesh.js";
import FacingIndicator from "../lib/gadget/FacingIndicator.js";
import Ellipsoid from "../lib/cesium/Core/Ellipsoid.js";

proj4.defs(
  epsg_4544,
  '+proj=tmerc +lat_0=0 +lon_0=105 +k=1 +x_0=500000 +y_0=0 +ellps=GRS80 +units=m +no_defs',
);

let _raycaster = new THREE.Raycaster();
const facingIndicator = new FacingIndicator();
const originFacing = new THREE.Vector3(0, 0, 1);
const markers = [];
const sphereGeo = new THREE.SphereGeometry(0.04);
const sphereMat = new THREE.MeshBasicMaterial({
  color: '#0b0',
  wireframe: true,
});
const lngLatMarker = createLocationSprite();
const sphereMesh = new THREE.Mesh(sphereGeo, sphereMat);
const tmpPoint = new THREE.Vector3();
const tmpV2 = new THREE.Vector2();
const mercatorProjection = new WebMercatorProjection();
const lngLatH = { longitude: 0, latitude: 0, height: 0 };
const txtOption = SimpleMarkEntity.getTxtOption();
txtOption.arrowHeight = 0;
txtOption.txtHeight = 3;
txtOption.bgOutline = false;
const locationToolTip = new SimpleMarkEntity('xxx...', txtOption);
locationToolTip.renderOrder = 13;

const locationTipTopOffset = 50;
const wallRaycaster = new THREE.Raycaster();

function getLabelDiffTxt(txtObj0, txtObj1) {
  const dx = (txtObj1.x - txtObj0.x).toFixed(3);
  const dy = (txtObj1.y - txtObj0.y).toFixed(3);
  const dz = (txtObj1.z - txtObj0.z).toFixed(3);
  return `dx: ${dx}, dy: ${dy}, dz: ${dz}`;
}

const txtOpt = SimpleMarkEntity.getTxtOption();
txtOpt.arrowHeight = 0;
txtOpt.txtHeight = 2;
txtOpt.fontSize = 0.35;
txtOpt.bgOutline = false;
const workAreaTip = new SimpleMarkEntity('xxx...', txtOpt);
workAreaTip.renderOrder = 13;

const sprayPointTipOption = SimpleMarkEntity.getTxtOption();
sprayPointTipOption.fontSize = 0.35;
const sprayPointTip = new SimpleMarkEntity('xxx...', sprayPointTipOption);
sprayPointTip.renderOrder = 14;

function showWorkAreaTip(world3d, worldPos, width, height, area, fontSize) {
  if (!workAreaTip.parent) {
    world3d.scene.add(workAreaTip);
  }
  workAreaTip.setEye(world3d.camera);
  workAreaTip.position.copy(worldPos);
  const widthStr = width.toFixed(2);
  const heightStr = height.toFixed(2);
  const areaStr = area.toFixed(2);
  const tipStr = `width: ${widthStr}m\nheight: ${heightStr}m\narea: ${areaStr}m²`; //sq.m.
  workAreaTip.visible = true;
  if (workAreaTip.text !== tipStr || workAreaTip.getFontSize() !== fontSize) {
    workAreaTip.updateFontSize(fontSize);
    workAreaTip.text = tipStr;
    workAreaTip.updateTextAndSize();
  }
}

function showWorkAreaTipByVO(world3d, pos, workArea) {
  showWorkAreaTip(
    world3d,
    pos,
    workArea.getAreaWidth(),
    workArea.getAreaHeight(),
    workArea.area,
    0.4,
  );
}
export function showAddingWorkAreaTip(world3d, rectOnPlane) {
  showWorkAreaTip(
    world3d,
    rectOnPlane.endPointWorld,
    rectOnPlane.width,
    rectOnPlane.height,
    rectOnPlane.area,
    0.15,
  );
}
export function hideWorkAreaTip() {
  workAreaTip.visible = false;
}

export function showSprayPointTip(world3d, worldPos, message) {
  if (!sprayPointTip.parent) {
    world3d.scene.add(sprayPointTip);
  }
  sprayPointTip.setEye(world3d.camera);
  sprayPointTip.position.copy(worldPos);
  sprayPointTip.visible = true;
  if (sprayPointTip.text !== message) {
    sprayPointTip.text = message;
    sprayPointTip.updateTextAndSize();
  }
}

export function hideSprayPointTip() {
  sprayPointTip.visible = false;
}

class MeasuringHeightPack {
  markHeight = new SimpleMarkEntity('1m');
  markUp = new SimpleMarkEntity('1m');
  markDown = new SimpleMarkEntity('1m');
  segment = createContourLineSegments(
    [new THREE.Vector3(0, 0, 0), new THREE.Vector3(0, 0, 1)],
    '#07a107',
  );
  height = 1;
  _plane1 = new THREE.Plane(new THREE.Vector3(0, 0, 1));
  _plane2 = new THREE.Plane(new THREE.Vector3(0, 0, 1));
  _p1 = new THREE.Vector3();
  _p2 = new THREE.Vector3();
  _p3 = new THREE.Vector3();

  constructor(camera) {
    this.markHeight.setEye(camera);
    this.markUp.setEye(camera);
    this.markDown.setEye(camera);
  }

  showPack(scene) {
    scene.add(this.markHeight, this.markUp, this.markDown, this.segment);
  }

  hidePack() {
    this.markHeight.removeFromParent();
    this.markUp.removeFromParent();
    this.markDown.removeFromParent();
    this.segment.removeFromParent();
  }

  get packShowing() {
    return this.segment.parent !== null;
  }

  /**
   * @param {MeasureUtil} measureUtil
   * @param {THREE.Raycaster} raycaster
   */
  updatePack(measureUtil, raycaster) {
    const plane1 = this._plane1;
    const plane2 = this._plane2;
    const n1 = measureUtil.grid.position.z;
    const n2 = measureUtil.gridTwo.position.z;
    plane1.constant = -n1;
    plane2.constant = -n2;
    const i1 = raycaster.ray.intersectPlane(plane1, this._p1);
    const i2 = raycaster.ray.intersectPlane(plane2, this._p2);
    if (!i1 && !i2) {
      return;
    }
    let intersectPoint = i1 || i2;
    if (i1 && i2) {
      const d1 = Math.abs(raycaster.ray.origin.z - i1.z);
      const d2 = Math.abs(raycaster.ray.origin.z - i2.z);
      intersectPoint = d1 < d2 ? i1 : i2;
    }
    let pos2;
    if (intersectPoint.z === n1) {
      pos2 = this._p3.copy(intersectPoint).setZ(n2);
    } else {
      pos2 = this._p3.copy(intersectPoint).setZ(n1);
    }
    const posUp = intersectPoint.z > pos2.z ? intersectPoint : pos2;
    const posDown = intersectPoint.z > pos2.z ? pos2 : intersectPoint;
    measureUtil.grid.position.copy(posDown);
    measureUtil.gridTwo.position.copy(posUp);
    this._updateItems(measureUtil, posUp, posDown);
  }

  /**
   * @param {MeasureUtil} measureUtil
   * @param {THREE.Vector3} posUp
   * @param {THREE.Vector3} posDown
   */
  _updateItems(measureUtil, posUp, posDown) {
    const height = posUp.z - posDown.z;
    const { markHeight, markUp, markDown, segment } = this;
    if (this.height !== height) {
      markHeight.text = height.toFixed(2) + 'm';
      markHeight.updateTextAndSize();
    }
    this.height = height;
    markHeight.position.copy(posUp).lerp(posDown, 0.5);
    const strUp = measureUtil.getPositionText(posUp);
    const strDown = measureUtil.getPositionText(posDown);
    if (strUp !== markUp.text) {
      markUp.text = strUp;
      markUp.updateTextAndSize();
    }
    if (strDown !== markDown.text) {
      markDown.text = strDown;
      markDown.updateTextAndSize();
    }
    markUp.position.copy(posUp);
    markDown.position.copy(posDown);
    const posAttr = segment.geometry.getAttribute('position');
    posAttr.setXYZ(0, posDown.x, posDown.y, posDown.z);
    posAttr.setXYZ(1, posUp.x, posUp.y, posUp.z);
    posAttr.needsUpdate = true;
  }
}

export default class MeasureUtil {
  config = {
    showAreaPosMarker: true,
  };
  world3d;
  labels = [];
  segments = [];
  distanceMarks = [];
  planeRefMarks = [];
  planeDistanceMarks = [];
  /**
   * @type {THREE.LineSegments|null}
   */
  curSegment = null;
  /**
   * @type {SimpleMarkEntity|null}
   */
  curDistanceMark = null;
  /**
   * 展示第一个约束平面
   * @type {THREE.GridHelper}
   */
  grid;
  // true 表示正在设置第一个约束平面
  _settingGrid = false;
  /**
   * 展示第二个约束平面
   * @type {THREE.GridHelper}
   */
  gridTwo;
  // true 表示正在设置第二个约束平面
  _settingGridTwo = false;

  _intersectingTile = false;
  /**
   * @type {MeasuringHeightPack}
   */
  measureHeightPack;
  /**
   * @type {SimpleMarkEntity}
   */
  activeLabel;
  activeSphere;
  // 测量工作区辅助平面到墙面的距离
  _measuringPlaneRef = false;

  constructor(world3d) {
    this.world3d = world3d;
    this.activeLabel = new SimpleMarkEntity('').setEye(world3d.camera);
    this.activeLabel.visible = false;
    this.activeLabel.renderOrder = 12;
    this.activeSphere = sphereMesh.clone();
    this.activeSphere.visible = false;
    world3d.scene.add(this.activeLabel, this.activeSphere);
    this.grid = new THREE.GridHelper(30, 120, 0xffffff, 0xffffff);
    this.grid.material.transparent = true;
    this.grid.material.opacity = 0.5;
    this.grid.rotation.x = Math.PI / 2;
    this.gridTwo = this.grid.clone();
    this.measureHeightPack = new MeasuringHeightPack(this.world3d.camera);
  }

  _updateAreaPosMarkers(vectors) {
    if (!this.config.showAreaPosMarker) {
      return;
    }
    markers.forEach((it) => it.removeFromParent());
    markers.length = 0;
    vectors.forEach((vector) => {
      const marker = getPositionMarker('', '#009d32', '#c40022');
      this.world3d.scene.add(marker);
      markers.push(marker);
      marker.position.copy(vector);
      const txtSprite = createTextSprite(this.getPositionText(vector));
      this.world3d.scene.add(txtSprite);
      markers.push(txtSprite);
      txtSprite.position.copy(vector);
    });
  }

  getLngLatText(vector) {
    // 墨卡托坐标转经纬度
    // mercatorProjection.unproject(vector, lngLatH);
    const loc = UnitsUtils.sphericalToDatums(vector.x, vector.y);
    const longitude = loc.longitude;
    const latitude = loc.latitude;
    const txt =
      longitude.toFixed(WorldConfig.measure.longitudeLen) +
      ', ' +
      latitude.toFixed(WorldConfig.measure.longitudeLen);
    return convertLngLatToNswe(txt);
  }

  getDroneTip(droneSprite) {
    const { sn, name, lng, lat } = droneSprite.userData;
    return `drone name: ${name}\ndrone sn: ${sn}\ndrone position: \n${lng}, ${lat}\n`;
  }

  getCartographicTip(vector, num = -1) {
    const mat = this.world3d._meta.toEarchCoordMat;
    const pos = vector.clone().applyMatrix4(mat);
    const cesiumCoord = new Cartesian3(pos.x, pos.y, pos.z);
    const cartographic = Cartographic.fromCartesian(cesiumCoord);
    const longitude = cartographic.longitude * r2d;
    const latitude = cartographic.latitude * r2d;
    const lngLat = longitude + ', ' + latitude;
    const arr = convertLngLatToNswe(lngLat).split(', ');
    const z = cartographic.height;
    let txt =
      'Longitude: ' +
      arr[0] +
      '\n' +
      'Latitude: ' +
      arr[1] +
      '\n' +
      'Altitude: ' +
      z.toFixed(WorldConfig.measure.heightLen) +
      '\n' +
      '';
    if (num >= 0) {
      txt += 'id: ' + num// + '\n'
    }
    return { txt, geoCoord: [longitude, latitude, z] };
  }

  getPositionText(vector) {
    const mat = this.world3d._meta.toEarchCoordMat;
    // 坐标转换：零变换世界坐标 转换为地球直角坐标系坐标；之所以需要这步转换是因为 offsetParent 经过了旋转的（用以抵消模型的原始姿态旋转）
    const pos = vector.clone().applyMatrix4(mat);
    // console.log('pos, ', pos, ', vector, ', vector)
    const cesiumCoord = new Cartesian3(pos.x, pos.y, pos.z);
    const cartographic = Cartographic.fromCartesian(cesiumCoord);
    const longitude = cartographic.longitude * r2d;
    const latitude = cartographic.latitude * r2d;
    const z = cartographic.height;
    // 球面上的二维经纬度坐标 根据特定的gis投影坐标系 转换为和大疆智图一致的投影坐标，便于测量3d模型上，点与点之间的距离，区域面积，体积
    const epsgCoord = proj4(epsg_4544, [longitude, latitude]);
    const [x, y] = epsgCoord;
    const txt =
      'height: ' +
      z.toFixed(WorldConfig.measure.heightLen) +
      '\n' +
      'longitude: ' + longitude.toFixed(WorldConfig.measure.longitudeLen) + '\n' +
      'latitude: ' + latitude.toFixed(WorldConfig.measure.longitudeLen) + '\n' +
      'x: ' +
      x.toFixed(WorldConfig.measure.xLen) +
      '\n' +
      'y: ' +
      y.toFixed(WorldConfig.measure.yLen) +
      '\n' +
      'wz: ' +
      vector.z.toFixed(WorldConfig.measure.xLen) +
      // '\n' +
      // 'wx: ' +
      // vector.x.toFixed(WorldConfig.measure.xLen) +
      // '\n' +
      // 'wy: ' +
      // vector.y.toFixed(WorldConfig.measure.xLen) +
      // '\n' +
      '';
    return txt; // {txt, x, y, z};
  }

  startShowCoord() {}

  endShowCoord() {}

  toggleGrid(showGrid) {
    if (showGrid) {
      let markLabel = this.activeLabel;
      this._settingGrid = this.labels.length === 0;
      if (!this._settingGrid) {
        markLabel = this.labels[this.labels.length - 1];
      }
      if (markLabel) {
        this.grid.position.copy(markLabel.position);
        this.world3d.scene.add(this.grid);
      }
    } else {
      this.grid.removeFromParent();
      this.gridTwo.removeFromParent();
    }
  }

  showingGrid() {
    return this.grid.parent !== null;
  }

  toggleHeightMeasuring(value) {
    // if (!this.world3d.store.stateMeasurePoint || !this.showingGrid() || this._settingGrid) {
    //   return;
    // }
    this._settingGridTwo = value;
    if (value) {
      this.world3d.scene.add(this.gridTwo);
      if (this.curDistanceMark) {
        this.curDistanceMark.removeFromParent();
        this.curDistanceMark = null;
      }
      if (this.curSegment) {
        this.curSegment.removeFromParent();
        this.curSegment = null;
      }
      this.measureHeightPack.showPack(this.world3d.scene);
    } else {
      this.gridTwo.removeFromParent();
      this.measureHeightPack.hidePack();
    }
    this.labels.forEach((it) => (it.visible = !this.measuringHeight()));
  }

  measuringHeight() {
    return this.gridTwo.parent !== null;
  }
  /**
   * 清除三维场景中的所有测量结果
   */
  clearMarks() {
    this.labels.forEach((it) => it.removeFromParent());
    this.planeDistanceMarks.forEach((it) => it.removeFromParent());
    this.segments.forEach((it) => it.removeFromParent());
    this.distanceMarks.forEach((it) => it.removeFromParent());
    this.labels.length = 0;
    this.planeDistanceMarks.length = 0;
    this.segments.length = 0;
    this.distanceMarks.length = 0;
    this.grid.removeFromParent();
    this.gridTwo.removeFromParent();
    this.measureHeightPack.hidePack();
  }

  showLocationTip(coord, tipStr, topOffset = 0) {
    if (!locationToolTip.parent) {
      this.world3d.scene.add(locationToolTip);
      locationToolTip.setEye(this.world3d.camera);
    }
    locationToolTip.position.copy(coord);
    if (topOffset !== 0) {
      const camera = this.world3d.camera;
      tmpPoint.copy(locationToolTip.position).project(camera);
      tmpPoint.y +=
        (locationTipTopOffset * window.devicePixelRatio) /
        this.world3d.renderer.getSize(tmpV2).y;
      tmpPoint.unproject(camera);
      locationToolTip.position.copy(tmpPoint);
    }
    locationToolTip.visible = true;
    if (locationToolTip.text !== tipStr) {
      locationToolTip.text = tipStr;
      locationToolTip.updateTextAndSize();
    }
  }

  toggleMeasuringPlaneRef() {
    this._measuringPlaneRef = !this._measuringPlaneRef;
  }

  togglePlaneRefMarks() {
    const pickPlaneRef = this.world3d.store.pickingPlaneRef();
    if (!pickPlaneRef) {
      return;
    }
    if (this.planeRefMarks.length) {
      this.planeRefMarks.forEach(it => it.removeFromParent());
      this.planeRefMarks.length = 0;
    } else {
      const corners = pickPlaneRef.corners;
      corners.forEach((point) => {
        const txt = this.getPositionText(point);
        const markMesh = new SimpleMarkEntity(txt).setEye(this.world3d.camera);
        markMesh.position.copy(point);
        this.world3d.scene.add(markMesh);
        this.planeRefMarks.push(markMesh);
      });
    }
  }

  toggleWorkAreaMarks() {
    const pickAreaMesh = this.world3d.store.pickingArea();
    if (!pickAreaMesh) {
      return;
    }
    const store = this.world3d.store;
    if (!pickAreaMesh.marks.length) {
      const workArea = pickAreaMesh.vo;
      let contour = workArea.verts[0];
      if (workArea.verts[1].length) {
        contour = contour.slice(0, workArea.verts[1][0]);
      }
      contour.forEach((point) => {
        const pos = new THREE.Vector3(point.x, point.y, 0).applyMatrix4(
          workArea.planeMat,
        );
        const txt = this.getPositionText(pos);
        const markMesh = new SimpleMarkEntity(txt).setEye(this.world3d.camera);
        markMesh.position.copy(pos);
        pickAreaMesh.marks.push(markMesh);
        store.areaMarks.push(markMesh);
        this.world3d.scene.add(markMesh);
      });
      workArea.updateLocalBox();
      const pos0 = workArea.localBox3.getCenter(new THREE.Vector3());
      const topPos = workArea.facing
        .clone()
        .multiplyScalar(0.5)
        .add(pos0.applyMatrix4(workArea.planeMat));
      const facing = workArea.facing;
      const normalInfo =
        'x: ' +
        facing.x.toFixed(8) +
        '\n' +
        'y: ' +
        facing.y.toFixed(8) +
        '\n' +
        'z: ' +
        facing.z.toFixed(8);
      const markFaceMesh = new SimpleMarkEntity(normalInfo).setEye(
        this.world3d.camera,
      );
      markFaceMesh.position.copy(topPos);
      pickAreaMesh.marks.push(markFaceMesh);
      this.world3d.scene.add(markFaceMesh);
      store.areaMarks.push(markFaceMesh);
    } else {
      const markVisible = pickAreaMesh.marks[0].visible;
      pickAreaMesh.marks.forEach((it) => (it.visible = !markVisible));
    }
  }

  _measuringPlaneRefDistance() {
    if (!this._measuringPlaneRef) {
      return false;
    }
    const store = this.world3d.store;
    const raycaster = this.world3d.mouseRaycaster;
    const meshes = store.planeRefMeshes.concat(store.areaMeshes);
    const intersects = raycaster.intersectObjects(meshes, false);
    if (!intersects.length) {
      return false;
    }
    const intersection = intersects[0];
    const planeRefMesh = intersection.object;
    const wallPoint = intersection.point;
    wallRaycaster.ray.origin.copy(wallPoint);
    if (planeRefMesh instanceof PlaneRefMesh) {
      wallRaycaster.ray.direction.copy(planeRefMesh.vo.plane.normal).negate();
    } else if (planeRefMesh instanceof WorkAreaMesh) {
      wallRaycaster.ray.direction.copy(planeRefMesh.vo.facing).negate();
    }
    const results = wallRaycaster.intersectObject(this.world3d.tiles.group, true);
    if (!results.length) {
      return false;
    }
    const distance = wallPoint.distanceTo(results[0].point);
    this.activeLabel.text = distance.toFixed(3) + 'm';
    this.activeLabel.position.copy(wallPoint);
    this.activeLabel.updateTextAndSize();
    this.activeLabel.visible = true;
    this.activeSphere.position.copy(wallPoint);
    this.activeSphere.visible = true;
    return true;
  }

  pointerMove4MeasurePoint(raycaster0) {
    let raycaster = raycaster0;
    if (this.showingGrid() && !this._settingGrid && !this.measuringHeight()) {
      _raycaster.ray.copy(raycaster.ray);
      _raycaster.ray.direction.z = 0;
      _raycaster.ray.origin.z = this.grid.position.z;
      raycaster = _raycaster;
    }
    // if (this.measuringHeight() && !this._settingGridTwo) {
    //   this.measureHeightPack.updatePack(this, raycaster0);
    //   return;
    // }
    let results = raycaster.intersectObject(this.world3d.tiles.group, true);
    if (!results.length) {
      this._intersectingTile = false;
      return;
    }
    this._intersectingTile = true;
    const intersect = results[0];
    facingIndicator.position.copy(intersect.point);
    facingIndicator.quaternion.setFromUnitVectors(
      originFacing,
      intersect.face.normal,
    );
    this.world3d.scene.add(facingIndicator);
    const txt = this.getPositionText(intersect.point);
    // const colorRanges = txt.split('').reduce((out, char, i) => {
    //   if (i === 0 || /\s/.test(char)) {
    //     out[i] = (Math.floor(Math.pow(Math.sin(i), 2) * 256) << 16)
    //       | (Math.floor(Math.pow(Math.sin(i + 1), 2) * 256) << 8)
    //       | (Math.floor(Math.pow(Math.sin(i + 2), 2) * 256))
    //     out[i] = '#' + new THREE.Color(out[i]).getHexString()
    //   }
    //   return out
    // }, {})
    // this.activeLabel._txtMesh.colorRanges = colorRanges
    this.activeLabel.text = txt;
    this.activeLabel.position.copy(intersect.point);
    this.activeLabel.updateTextAndSize();
    this.activeLabel.visible = true;

    // this.activeSphere.position.copy(intersect.point);
    // this.activeSphere.visible = true;
    if (this._settingGrid) {
      this.grid.position.copy(intersect.point);
    } else if (this._settingGridTwo) {
      this.gridTwo.position.copy(intersect.point);
      if (this.measuringHeight()) {
        if (!this.measureHeightPack.packShowing) {
          this.measureHeightPack.showPack(this.world3d.scene);
        }
        this.measureHeightPack.updatePack(this, raycaster0);
      }
    }

    if (this.labels.length > 0 && !this.measuringHeight()) {
      const label = this.activeLabel;
      const latestLabel = this.labels[this.labels.length - 1];
      const distance = latestLabel.position.distanceTo(label.position);
      const distanceTxt = distance.toFixed(2) + 'm';
      if (!this.curSegment) {
        const segment = createContourLineSegments(
          [latestLabel.position, label.position],
          '#07a107',
        );
        const dLabel = new SimpleMarkEntity(distanceTxt).setEye(
          this.world3d.camera,
        );
        dLabel.position.copy(latestLabel.position).lerp(label.position, 0.5);
        this.curSegment = segment;
        this.curDistanceMark = dLabel;
        this.world3d.scene.add(segment, dLabel);
      } else {
        const posAttr = this.curSegment.geometry.getAttribute('position');
        posAttr.setXYZ(1, label.position.x, label.position.y, label.position.z);
        posAttr.needsUpdate = true;
        this.curDistanceMark.position
          .copy(latestLabel.position)
          .lerp(label.position, 0.5);
        this.curDistanceMark.text = distanceTxt;
        this.curDistanceMark.updateTextAndSize();
      }
    }
  }

  // 鼠标按下的回调
  pointerDown(event) {}

  pointerMove(event) {
    this.activeLabel.visible = false;
    this.activeSphere.visible = false;
    locationToolTip.visible = false;
    const store = this.world3d.store;
    let raycaster = this.world3d.mouseRaycaster;
    if (store.stateFree) {
      let intersects;
      if (store._locationSpriteVisible) {
        const droneSprites = store.droneSprites.filter((it) => it.visible);
        intersects = raycaster.intersectObjects(droneSprites);
        if (intersects.length) {
          const intersectDrone = intersects[0].object;
          const locTip = this.getDroneTip(intersectDrone);
          this.showLocationTip(
            intersects[0].point,
            locTip,
            locationTipTopOffset,
          );
        } else {
          intersects = raycaster.intersectObjects(store.locationSprites);
          if (intersects.length) {
            const intersection = intersects[0];
            const locTip =
              'Coordinates:\n' + intersection.object.userData.tipPos;
            this.showLocationTip(intersects[0].point, locTip);
          }
        }
      } else {
        store.curHoverPoint = null;
        intersects = raycaster.intersectObjects(
          store.calibrationPoints.concat(store.flyHomePoints),
        );
        if (intersects.length) {
          const intersection = intersects[0];
          store.curHoverPoint = intersection.object;
          this.showLocationTip(
            intersection.point,
            intersection.object.userData.tipPos,
          );
        } else {
          if (this._measuringPlaneRef) {
            hideWorkAreaTip();
          } else {
            // 工作区 长 宽 面积 tip
            intersects = raycaster.intersectObjects(store.areaMeshes, false);
            if (intersects.length) {
              const worldPos = intersects[0].point;
              const vo = intersects[0].object.vo;
              showWorkAreaTipByVO(this.world3d, worldPos, vo);
            } else {
              hideWorkAreaTip();
            }
          }
        }
      }
    } else if (store.statePickLngLat) {
      raycaster.ray.intersectPlane(this.world3d._mapViewHitPlane, tmpPoint);
      // if (!lngLatMarker.parent) {
      //   this.world3d.scene.add(lngLatMarker);
      // }
      // lngLatMarker.position.copy(tmpPoint);
      const txt = this.getLngLatText(tmpPoint);
      // localStorage.setItem('DefaultLngLat', txt);
      this.activeLabel.position.copy(tmpPoint);
      this.activeLabel.text = txt;
      this.activeLabel.updateTextAndSize();
      this.activeLabel.visible = true;
      return;
    }

    if (this._measuringPlaneRefDistance()) {
      return;
    }
    if (store.stateMeasurePoint) {
      this.pointerMove4MeasurePoint(raycaster);
    }
  }

  pointerUpMoved(event) {}

  pointerUpUnmoved(event) {
    const store = this.world3d.store;
    if (event.button === 2) {
      // mouse right button down
      if (store.stateMeasurePoint || store.statePickLngLat) {
        this.endShowCoord();
        store.freeState();
        if (this.curSegment) {
          this.curSegment.removeFromParent();
          this.curSegment = null;
        }
        if (this.curDistanceMark) {
          this.curDistanceMark.removeFromParent();
          this.curDistanceMark = null;
        }
        facingIndicator.removeFromParent();
      }
      return;
    }
    if (this._measuringPlaneRef && this.activeLabel.visible) {
      const label = new SimpleMarkEntity(this.activeLabel.text).setEye(
        this.world3d.camera,
      );
      label.position.copy(this.activeLabel.position);
      this.world3d.scene.add(label);
      this.planeDistanceMarks.push(label);
      return;
    }
    const droneSprites = store.droneSprites.filter((it) => it.visible);
    if (
      store.stateFree &&
      store._locationSpriteVisible &&
      droneSprites.length
    ) {
      const raycaster = this.world3d.mouseRaycaster;
      const intersects = raycaster.intersectObjects(droneSprites);
      if (intersects.length) {
        const intersectDrone = intersects[0].object;
        // World3dEvent.droneSelected.value = intersectDrone.userData;
        // this.world3d.scene.dispatchEvent(World3dEvent.droneSelected);
      }
    }
    if (store.statePickLngLat) {
      // World3dEvent.pickLngLatFinish.value.txt = this.activeLabel.text;
      // World3dEvent.pickLngLatFinish.value.tipPos =
      //   'Coordinates:\n' + this.getLngLatText(this.activeLabel.position);
      // World3dEvent.pickLngLatFinish.value.pos.copy(this.activeLabel.position);
      // this.world3d.scene.dispatchEvent(World3dEvent.pickLngLatFinish);
      store.freeState();
      if (!lngLatMarker.parent) {
        this.world3d.scene.add(lngLatMarker);
      }
      lngLatMarker.position.copy(this.activeLabel.position);
      return;
    }
    if (!store.stateMeasurePoint) {
      return;
    }
    if (!this._intersectingTile) {
      return;
    }

    if (this._settingGrid) {
      this._settingGrid = false;
    } else if (this._settingGridTwo) {
      this._settingGridTwo = false;
      return;
    }

    const label = this.activeLabel.cloneMark();
    this.world3d.scene.add(label);
    this.labels.push(label);
    if (this.labels.length > 1 && this.curSegment) {
      this.segments.push(this.curSegment);
      this.distanceMarks.push(this.curDistanceMark);
      this.curSegment = null;
      this.curDistanceMark = null;
    }
  }
}
